#include<bits/stdc++.h> // 包含了 bitset, cmath, algorithm, iostream 等常用库
using namespace std;

const int N = 1e5 + 5;    // 数组和查询数量的最大值上限
const int VAL_MAX = 1e5; // 题目中数值 a_i 和 x 的上限

int n, m, a[N], sq;      // n: 数组元素个数, m: 查询个数, a[]: 输入数组, sq: 莫队块大小
struct QueryNode {       // 定义查询结构体
    int l, r, id;        // 查询区间的左右端点 [l, r], 原始查询的编号id
    int type, x_val;     // 操作类型 (1, 2, 或 3), 操作的目标值x
} b[N];                  // 存储所有查询的数组

// 莫队排序的比较函数
// (l-1)/sq 计算的是0-indexed的块编号
int cmp(QueryNode qa, QueryNode qb) {
    int block_qa = (qa.l - 1) / sq; // 查询qa的左端点所在块的编号
    int block_qb = (qb.l - 1) / sq; // 查询qb的左端点所在块的编号
    if (block_qa != block_qb) {     // 如果不在同一个块
        return block_qa < block_qb; // 按块编号升序排序
    }
    // 如果在同一个块，进行奇偶优化排序
    // 偶数块（0, 2, 4...）按右端点升序
    // 奇数块（1, 3, 5...）按右端点降序
    if (block_qa % 2 == 0) {
        return qa.r < qb.r;
    }
    return qa.r > qb.r;
}

int current_l, current_r; // 莫队当前维护的窗口的左右指针 [current_l, current_r]
int cnt[VAL_MAX + 1];     // cnt[val] 记录数值 val 在当前窗口中出现的次数
bool ans[N];              // ans[id] 存储第 id 个原始查询的答案 (true对应"hana", false对应"bi")

bitset<VAL_MAX + 1> S;    // S[v] = 1 表示数值 v 当前存在于窗口中
bitset<VAL_MAX + 1> Sr;   // Sr[VAL_MAX - v] = 1 表示数值 v 当前存在于窗口中 (用于和查询优化)

// 将数组中下标为 p_idx 的元素加入当前窗口
void add(int p_idx) {
    int val = a[p_idx];       // 获取要添加的数值
    if (++cnt[val] == 1) {    // 该数值的计数加1；如果计数从0变为1，说明该数值是新加入窗口的
        S[val] = 1;           // 在S中标记val存在
        Sr[VAL_MAX - val] = 1;// 在Sr中标记val存在 (对应反向索引)
    }
}

// 将数组中下标为 p_idx 的元素从当前窗口移除
void del(int p_idx) {
    int val = a[p_idx];       // 获取要移除的数值
    if (--cnt[val] == 0) {    // 该数值的计数减1；如果计数从1变为0，说明该数值已完全从窗口中移除
        S[val] = 0;           // 在S中取消标记val
        Sr[VAL_MAX - val] = 0;// 在Sr中取消标记val
    }
}

int main() {
    // 使用cin/cout进行快速IO
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n >> m; // 输入数组大小和查询数量
    for (int i = 1; i <= n; i++) cin >> a[i]; // 输入数组元素 (题目中数组下标从1开始)

    sq = sqrt(n); // 计算莫队算法的块大小
    if (sq == 0) sq = 1; // 防止n过小时块大小为0导致除零错误

    for (int i = 1; i <= m; i++) { // 输入m个查询
        cin >> b[i].type >> b[i].l >> b[i].r >> b[i].x_val;
        b[i].id = i; // 记录每个查询的原始编号，以便按顺序输出答案
    }

    sort(b + 1, b + m + 1, cmp); // 对所有查询按莫队规则进行排序

    current_l = 1; // 莫队窗口左指针初始化
    current_r = 0; // 莫队窗口右指针初始化 (当前为空区间[1,0])

    for (int i = 1; i <= m; i++) { // 依次处理排序后的查询
        int tl = b[i].l, tr = b[i].r; // 当前查询的目标区间 [tl, tr]
        int type = b[i].type;         // 当前查询的操作类型
        int x = b[i].x_val;           // 当前查询的操作参数x

        // 根据目标区间 [tl, tr] 调整当前窗口 [current_l, current_r]
        while (current_l > tl) add(--current_l); // 窗口左端点需要向左移动，添加新元素
        while (current_r < tr) add(++current_r); // 窗口右端点需要向右移动，添加新元素
        while (current_l < tl) del(current_l++); // 窗口左端点需要向右移动，移除旧元素
        while (current_r > tr) del(current_r--); // 窗口右端点需要向左移动，移除旧元素

        bool current_query_ans = false; // 当前查询的答案，默认为false (即 "bi")
        if (type == 1) { // 操作1: 差为 x (是否存在 a, b 使得 a - b = x)
            // (S & (S << x)) 如果结果的第k位为1, 表示 S[k]=1 (k存在) 且 (S<<x)[k]=1 (即原S[k-x]=1, k-x存在)
            current_query_ans = (S & (S << x)).any();
        } else if (type == 2) { // 操作2: 和为 x (是否存在 a, b 使得 a + b = x)
            // 如果x的值超出合理范围 [0, 2*VAL_MAX]，则不可能找到和为x的两个非负数
            if (x < 0 || x > 2 * VAL_MAX) {
                current_query_ans = false;
            } else {
                // (S & (Sr >> (VAL_MAX - x))) 如果结果的第k位为1, 表示 S[k]=1 (k存在)
                // 且 (Sr>>(VAL_MAX-x))[k]=1 (即数值 x-k 存在)
                current_query_ans = (S & (Sr >> (VAL_MAX - x))).any();
            }
        } else { // 操作3: 积为 x (是否存在 a, b 使得 a * b = x)
            // 遍历x的因子。只需遍历到sqrt(x)即可。
            // j*j可能会超过int范围，故用long long
            for (long long j = 1; j * j <= x; ++j) {
                if (x % j == 0) { // 如果j是x的因子
                    int factor1 = j;
                    int factor2 = x / j;
                    // 检查两个因子是否都存在于当前窗口中
                    // 由于x和a_i均 <= VAL_MAX，它们的因子也都在bitset的有效索引范围内 [0, VAL_MAX]
                    if (S[factor1] && S[factor2]) {
                        current_query_ans = true; // 找到满足条件的数对
                        break;                    // 找到一组即可退出循环
                    }
                }
            }
        }
        ans[b[i].id] = current_query_ans; // 将当前查询的答案存入对应原始id的位置
    }

    for (int i = 1; i <= m; i++) { // 按原始查询顺序输出答案
        if (ans[i]) cout << "hana" << "\n"; // 如果为true，输出 "hana"
        else cout << "bi" << "\n";        // 如果为false，输出 "bi"
    }

    return 0;
}